package com.example.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author zhangs
 * @version v1.0
 * @decription
 * @date 2021/4/6 9:00
 **/
public class MethodDemo {
    // 可变参数静态方法
    public static Integer staticMethod(String... ts) {
        for (String t : ts) {
            System.out.println(t);
        }
        System.out.println("静态方法！");
        return ts.length;
    }

    // 参数为数组，返回值为参数化类型
    private List<String> get(String[] strings) {
        ArrayList<String> list = new ArrayList<>(Arrays.asList(strings));
        return list;
    }

    public int m1(int i, Integer j) {
        System.out.println("实例方法！");
        return i + j;
    }

    public static void main(String[] args) {
        Class<MethodDemo> clazz = MethodDemo.class;
        // 获取所有的方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            StringBuilder sb = new StringBuilder();
            // 获取方法修饰符
            int modifiers = method.getModifiers();
            sb.append(Modifier.toString(modifiers)).append(" ");
            // 获取方法返回值
            Type type = method.getGenericReturnType();
            sb.append(type.getTypeName()).append(" ");
            // 获取方法名称
            String name = method.getName();
            sb.append(name).append("(");
            // 获取方法参数
            Type[] gpts = method.getGenericParameterTypes();
            for (Type gpt : gpts) {
                // 获取参数类型
                sb.append(gpt.getTypeName()).append(",");
            }
            sb.delete(sb.lastIndexOf(","), sb.length());
            sb.append(")");
            System.out.println(sb.toString());
            // 方法是否为可变参数
            System.out.println("方法为可变参数："+method.isVarArgs());
        }

        // 执行可变参数静态方法
        try {
            Method method = clazz.getDeclaredMethod("staticMethod", String[].class);
            // 可变参数的调用方式：必须先创建相应的数组，然后使用Object数组包裹上述创建的数组
            // 因为java反射内部实现做了个参数个数为1的判断，如果参数长度不为1，抛出异常
            String[] strings = {"世界", "珍珠"};
            Object[] objects = {strings};
            // 静态方法调用时，不需要指定实例
            Object invoke = method.invoke(null, objects);
            System.out.println(invoke);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 执行实例方法，参数为数组，返回值为参数化类型
        try {
            // 实例方法执行前必须先创建对象
            MethodDemo methodDemo = clazz.getConstructor().newInstance();
            // 获得实例方法
            Method get = clazz.getDeclaredMethod("get", String[].class);
            // 绕过权限控制
            get.setAccessible(true);
            // 数组的调用和可变参数一致，都需要使用在传入的数组外面包裹一个Object数组
            List<String> invoke = (List<String>) get.invoke(methodDemo, new Object[]{new String[]{"世界", "美好"}});
            // 将函数的返回值转换成实际对象
            invoke.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
